From: Christian Marangi Date: Thu, 27 Nov 2025 21:00:03 +0000 (+0100) Subject: generic: backport support for faux base driver X-Git-Url: http://git.openwrt.org/%22https:/collectd.org/%22http:/www.crowdsec.net//%22https%22/%22https:/collectd.org/%22http:/www.crowdsec.net/%22https%22?a=commitdiff_plain;h=2740ebdd60274a8b4dafe6a947387f0dcb7ac167;p=openwrt%2Fopenwrt.git generic: backport support for faux base driver Backport support for faux base driver needed for backports package to compile with kernel 6.18. Link: https://github.com/openwrt/openwrt/pull/20964 Signed-off-by: Christian Marangi --- diff --git a/target/linux/generic/backport-6.12/900-v6.14-driver-core-add-a-faux-bus-for-use-when-a-simple-dev.patch b/target/linux/generic/backport-6.12/900-v6.14-driver-core-add-a-faux-bus-for-use-when-a-simple-dev.patch new file mode 100644 index 0000000000..1ada8a6ef4 --- /dev/null +++ b/target/linux/generic/backport-6.12/900-v6.14-driver-core-add-a-faux-bus-for-use-when-a-simple-dev.patch @@ -0,0 +1,386 @@ +From 35fa2d88ca9481e5caf533d58b99ca259c63b2fe Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman +Date: Mon, 10 Feb 2025 13:30:25 +0100 +Subject: [PATCH] driver core: add a faux bus for use when a simple device/bus + is needed +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Many drivers abuse the platform driver/bus system as it provides a +simple way to create and bind a device to a driver-specific set of +probe/release functions. Instead of doing that, and wasting all of the +memory associated with a platform device, here is a "faux" bus that +can be used instead. + +Reviewed-by: Jonathan Cameron +Reviewed-by: Danilo Krummrich +Reviewed-by: Lyude Paul +Reviewed-by: Thomas Weißschuh +Reviewed-by: Zijun Hu +Link: https://lore.kernel.org/r/2025021026-atlantic-gibberish-3f0c@gregkh +Signed-off-by: Greg Kroah-Hartman +--- + Documentation/driver-api/infrastructure.rst | 6 + + drivers/base/Makefile | 2 +- + drivers/base/base.h | 1 + + drivers/base/faux.c | 232 ++++++++++++++++++++ + drivers/base/init.c | 1 + + include/linux/device/faux.h | 69 ++++++ + 6 files changed, 310 insertions(+), 1 deletion(-) + create mode 100644 drivers/base/faux.c + create mode 100644 include/linux/device/faux.h + +--- a/Documentation/driver-api/infrastructure.rst ++++ b/Documentation/driver-api/infrastructure.rst +@@ -41,6 +41,12 @@ Device Drivers Base + .. kernel-doc:: drivers/base/class.c + :export: + ++.. kernel-doc:: include/linux/device/faux.h ++ :internal: ++ ++.. kernel-doc:: drivers/base/faux.c ++ :export: ++ + .. kernel-doc:: drivers/base/node.c + :internal: + +--- a/drivers/base/Makefile ++++ b/drivers/base/Makefile +@@ -6,7 +6,7 @@ obj-y := component.o core.o bus.o dd.o + cpu.o firmware.o init.o map.o devres.o \ + attribute_container.o transport_class.o \ + topology.o container.o property.o cacheinfo.o \ +- swnode.o ++ swnode.o faux.o + obj-$(CONFIG_AUXILIARY_BUS) += auxiliary.o + obj-$(CONFIG_DEVTMPFS) += devtmpfs.o + obj-y += power/ +--- a/drivers/base/base.h ++++ b/drivers/base/base.h +@@ -138,6 +138,7 @@ int hypervisor_init(void); + static inline int hypervisor_init(void) { return 0; } + #endif + int platform_bus_init(void); ++int faux_bus_init(void); + void cpu_dev_init(void); + void container_dev_init(void); + #ifdef CONFIG_AUXILIARY_BUS +--- /dev/null ++++ b/drivers/base/faux.c +@@ -0,0 +1,232 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Copyright (c) 2025 Greg Kroah-Hartman ++ * Copyright (c) 2025 The Linux Foundation ++ * ++ * A "simple" faux bus that allows devices to be created and added ++ * automatically to it. This is to be used whenever you need to create a ++ * device that is not associated with any "real" system resources, and do ++ * not want to have to deal with a bus/driver binding logic. It is ++ * intended to be very simple, with only a create and a destroy function ++ * available. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "base.h" ++ ++/* ++ * Internal wrapper structure so we can hold a pointer to the ++ * faux_device_ops for this device. ++ */ ++struct faux_object { ++ struct faux_device faux_dev; ++ const struct faux_device_ops *faux_ops; ++}; ++#define to_faux_object(dev) container_of_const(dev, struct faux_object, faux_dev.dev) ++ ++static struct device faux_bus_root = { ++ .init_name = "faux", ++}; ++ ++static int faux_match(struct device *dev, const struct device_driver *drv) ++{ ++ /* Match always succeeds, we only have one driver */ ++ return 1; ++} ++ ++static int faux_probe(struct device *dev) ++{ ++ struct faux_object *faux_obj = to_faux_object(dev); ++ struct faux_device *faux_dev = &faux_obj->faux_dev; ++ const struct faux_device_ops *faux_ops = faux_obj->faux_ops; ++ int ret = 0; ++ ++ if (faux_ops && faux_ops->probe) ++ ret = faux_ops->probe(faux_dev); ++ ++ return ret; ++} ++ ++static void faux_remove(struct device *dev) ++{ ++ struct faux_object *faux_obj = to_faux_object(dev); ++ struct faux_device *faux_dev = &faux_obj->faux_dev; ++ const struct faux_device_ops *faux_ops = faux_obj->faux_ops; ++ ++ if (faux_ops && faux_ops->remove) ++ faux_ops->remove(faux_dev); ++} ++ ++static const struct bus_type faux_bus_type = { ++ .name = "faux", ++ .match = faux_match, ++ .probe = faux_probe, ++ .remove = faux_remove, ++}; ++ ++static struct device_driver faux_driver = { ++ .name = "faux_driver", ++ .bus = &faux_bus_type, ++ .probe_type = PROBE_FORCE_SYNCHRONOUS, ++}; ++ ++static void faux_device_release(struct device *dev) ++{ ++ struct faux_object *faux_obj = to_faux_object(dev); ++ ++ kfree(faux_obj); ++} ++ ++/** ++ * faux_device_create_with_groups - Create and register with the driver ++ * core a faux device and populate the device with an initial ++ * set of sysfs attributes. ++ * @name: The name of the device we are adding, must be unique for ++ * all faux devices. ++ * @parent: Pointer to a potential parent struct device. If set to ++ * NULL, the device will be created in the "root" of the faux ++ * device tree in sysfs. ++ * @faux_ops: struct faux_device_ops that the new device will call back ++ * into, can be NULL. ++ * @groups: The set of sysfs attributes that will be created for this ++ * device when it is registered with the driver core. ++ * ++ * Create a new faux device and register it in the driver core properly. ++ * If present, callbacks in @faux_ops will be called with the device that ++ * for the caller to do something with at the proper time given the ++ * device's lifecycle. ++ * ++ * Note, when this function is called, the functions specified in struct ++ * faux_ops can be called before the function returns, so be prepared for ++ * everything to be properly initialized before that point in time. ++ * ++ * Return: ++ * * NULL if an error happened with creating the device ++ * * pointer to a valid struct faux_device that is registered with sysfs ++ */ ++struct faux_device *faux_device_create_with_groups(const char *name, ++ struct device *parent, ++ const struct faux_device_ops *faux_ops, ++ const struct attribute_group **groups) ++{ ++ struct faux_object *faux_obj; ++ struct faux_device *faux_dev; ++ struct device *dev; ++ int ret; ++ ++ faux_obj = kzalloc(sizeof(*faux_obj), GFP_KERNEL); ++ if (!faux_obj) ++ return NULL; ++ ++ /* Save off the callbacks so we can use them in the future */ ++ faux_obj->faux_ops = faux_ops; ++ ++ /* Initialize the device portion and register it with the driver core */ ++ faux_dev = &faux_obj->faux_dev; ++ dev = &faux_dev->dev; ++ ++ device_initialize(dev); ++ dev->release = faux_device_release; ++ if (parent) ++ dev->parent = parent; ++ else ++ dev->parent = &faux_bus_root; ++ dev->bus = &faux_bus_type; ++ dev->groups = groups; ++ dev_set_name(dev, "%s", name); ++ ++ ret = device_add(dev); ++ if (ret) { ++ pr_err("%s: device_add for faux device '%s' failed with %d\n", ++ __func__, name, ret); ++ put_device(dev); ++ return NULL; ++ } ++ ++ return faux_dev; ++} ++EXPORT_SYMBOL_GPL(faux_device_create_with_groups); ++ ++/** ++ * faux_device_create - create and register with the driver core a faux device ++ * @name: The name of the device we are adding, must be unique for all ++ * faux devices. ++ * @parent: Pointer to a potential parent struct device. If set to ++ * NULL, the device will be created in the "root" of the faux ++ * device tree in sysfs. ++ * @faux_ops: struct faux_device_ops that the new device will call back ++ * into, can be NULL. ++ * ++ * Create a new faux device and register it in the driver core properly. ++ * If present, callbacks in @faux_ops will be called with the device that ++ * for the caller to do something with at the proper time given the ++ * device's lifecycle. ++ * ++ * Note, when this function is called, the functions specified in struct ++ * faux_ops can be called before the function returns, so be prepared for ++ * everything to be properly initialized before that point in time. ++ * ++ * Return: ++ * * NULL if an error happened with creating the device ++ * * pointer to a valid struct faux_device that is registered with sysfs ++ */ ++struct faux_device *faux_device_create(const char *name, ++ struct device *parent, ++ const struct faux_device_ops *faux_ops) ++{ ++ return faux_device_create_with_groups(name, parent, faux_ops, NULL); ++} ++EXPORT_SYMBOL_GPL(faux_device_create); ++ ++/** ++ * faux_device_destroy - destroy a faux device ++ * @faux_dev: faux device to destroy ++ * ++ * Unregisters and cleans up a device that was created with a call to ++ * faux_device_create() ++ */ ++void faux_device_destroy(struct faux_device *faux_dev) ++{ ++ struct device *dev = &faux_dev->dev; ++ ++ if (!faux_dev) ++ return; ++ ++ device_del(dev); ++ ++ /* The final put_device() will clean up the memory we allocated for this device. */ ++ put_device(dev); ++} ++EXPORT_SYMBOL_GPL(faux_device_destroy); ++ ++int __init faux_bus_init(void) ++{ ++ int ret; ++ ++ ret = device_register(&faux_bus_root); ++ if (ret) { ++ put_device(&faux_bus_root); ++ return ret; ++ } ++ ++ ret = bus_register(&faux_bus_type); ++ if (ret) ++ goto error_bus; ++ ++ ret = driver_register(&faux_driver); ++ if (ret) ++ goto error_driver; ++ ++ return ret; ++ ++error_driver: ++ bus_unregister(&faux_bus_type); ++ ++error_bus: ++ device_unregister(&faux_bus_root); ++ return ret; ++} +--- a/drivers/base/init.c ++++ b/drivers/base/init.c +@@ -32,6 +32,7 @@ void __init driver_init(void) + /* These are also core pieces, but must come after the + * core core pieces. + */ ++ faux_bus_init(); + of_core_init(); + platform_bus_init(); + auxiliary_bus_init(); +--- /dev/null ++++ b/include/linux/device/faux.h +@@ -0,0 +1,69 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * Copyright (c) 2025 Greg Kroah-Hartman ++ * Copyright (c) 2025 The Linux Foundation ++ * ++ * A "simple" faux bus that allows devices to be created and added ++ * automatically to it. This is to be used whenever you need to create a ++ * device that is not associated with any "real" system resources, and do ++ * not want to have to deal with a bus/driver binding logic. It is ++ * intended to be very simple, with only a create and a destroy function ++ * available. ++ */ ++#ifndef _FAUX_DEVICE_H_ ++#define _FAUX_DEVICE_H_ ++ ++#include ++#include ++ ++/** ++ * struct faux_device - a "faux" device ++ * @dev: internal struct device of the object ++ * ++ * A simple faux device that can be created/destroyed. To be used when a ++ * driver only needs to have a device to "hang" something off. This can be ++ * used for downloading firmware or other basic tasks. Use this instead of ++ * a struct platform_device if the device has no resources assigned to ++ * it at all. ++ */ ++struct faux_device { ++ struct device dev; ++}; ++#define to_faux_device(x) container_of_const((x), struct faux_device, dev) ++ ++/** ++ * struct faux_device_ops - a set of callbacks for a struct faux_device ++ * @probe: called when a faux device is probed by the driver core ++ * before the device is fully bound to the internal faux bus ++ * code. If probe succeeds, return 0, otherwise return a ++ * negative error number to stop the probe sequence from ++ * succeeding. ++ * @remove: called when a faux device is removed from the system ++ * ++ * Both @probe and @remove are optional, if not needed, set to NULL. ++ */ ++struct faux_device_ops { ++ int (*probe)(struct faux_device *faux_dev); ++ void (*remove)(struct faux_device *faux_dev); ++}; ++ ++struct faux_device *faux_device_create(const char *name, ++ struct device *parent, ++ const struct faux_device_ops *faux_ops); ++struct faux_device *faux_device_create_with_groups(const char *name, ++ struct device *parent, ++ const struct faux_device_ops *faux_ops, ++ const struct attribute_group **groups); ++void faux_device_destroy(struct faux_device *faux_dev); ++ ++static inline void *faux_device_get_drvdata(const struct faux_device *faux_dev) ++{ ++ return dev_get_drvdata(&faux_dev->dev); ++} ++ ++static inline void faux_device_set_drvdata(struct faux_device *faux_dev, void *data) ++{ ++ dev_set_drvdata(&faux_dev->dev, data); ++} ++ ++#endif /* _FAUX_DEVICE_H_ */